<template>
  <view class="header" :style="{ height: (isBoxHeight ? 0 : headerHeight) + 'px', zIndex }">
    <view :class="{ fixed }" :style="{ height: headerHeight + 'px' }">
      <view class="back" :style="{ background: backColor, opacity }" :class="getBackClass" />
      <view class="box">
        <view :style="{ height: statusBarHeight + 'px' }" class="status-bar" />
        <view class="con" :style="{ height: conHeight + 'px' }">
          <slot name="header">
            <button
              class="hb-absolute hb-ml-3 hb-h-full hb-flex hb-justify-center hb-items-center hb-bg-transparent after:hb-border-none hover:hb-bg-transparent"
              @click="goBack"
              v-if="isGoBack"
            >
              <template v-if="goBackIcon">
                <view
                  class="ali-icon"
                  :style="{ color, fontSize: '40rpx', 'padding-left': '10rpx' }"
                >
                  {{ goBackIcon }}
                </view>
              </template>
              <template v-else>
                <view v-if="pageLength > 1" class="ali-icon" :style="{ color }">&#xe6aa;</view>
                <view v-else class="ali-icon" :style="{ color, fontSize: '40rpx' }">&#xe6ca;</view>
              </template>
            </button>
            <view
              class="con-box"
              :style="{ color, justifyContent: customTitle ? 'unset' : 'center' }"
            >
              <view v-if="!customTitle" class="con-title text-overflow-1 hb-h-full">
                <slot name="title">{{ title }}</slot>
              </view>
              <slot name="customTitle" :opacity="opacity" />
            </view>
          </slot>
        </view>
        <view class="bottom-box">
          <slot />
        </view>
      </view>
    </view>
  </view>
</template>

<script lang="ts" setup>
  import { propTypes } from '@/utils/propTypes';
  import { ref, watch, nextTick, getCurrentInstance, toRaw, type PropType, useSlots } from 'vue';
  import { hexToRGB } from '@/utils/color';
  import { onPageScroll } from '@dcloudio/uni-app';
  import { SceneValuesEnum } from '@/enums/sceneValuesEnum';

  const { customTitle } = useSlots();

  const _ = defineProps({
    modelValue: propTypes.number,
    opacity: propTypes.number,
    title: propTypes.string.def(''),
    titleColor: propTypes.string.def('#000000'),
    varietyTitleColor: propTypes.string.def('#ffffff'),
    fixed: propTypes.bool.def(true),
    transparent: {
      type: String as PropType<'always' | 'auto' | 'none'>,
      default: 'none',
    },
    background: propTypes.string,
    backgroundColor: propTypes.string.def('#ffffff'),
    offsetHeight: propTypes.number,
    isBoxHeight: propTypes.bool,
    isGoBack: propTypes.bool.def(true),
    isCustomBack: propTypes.bool.def(false),
    isBoxShadow: propTypes.bool.def(true),
    goBackIcon: propTypes.string,
    data: [Object, Array, String, Number],
    zIndex: propTypes.number.def(999),
    /**
     * 插槽默认内容高度, 用于页面异步渲染时获取BottomBox高度慢于页面异步函数
     * 单位 => rpx 使用uni.upx2px 转换至px
     */
    defaultSlotContentHeight: propTypes.number.def(0),
  });

  const emit = defineEmits(['update:modelValue', 'goBack', 'update:opacity']);
  const ins: any = getCurrentInstance();

  const pageLength = ref(getCurrentPages().length);
  const SysInfo = uni.getSystemInfoSync();
  const inIos = false; //isNewIphone(SysInfo.model);
  const baseColor = hexToRGB(_.titleColor);
  const varietyColor = hexToRGB(_.varietyTitleColor);

  const color = ref<string>('rgb(' + baseColor.join(',') + ')');
  const opacity = ref<number>(_.transparent === 'none' ? 1 : 0);
  emit('update:opacity', opacity.value);

  const backColor = ref<string>(
    _.background || `rgba(${hexToRGB(_.backgroundColor).join(',')},${inIos ? '0.9' : '1'})`,
  );
  const statusBarHeight = ref<number>(SysInfo.statusBarHeight || 10);
  const conHeight = ref<number>(44);

  // #ifdef MP
  let { height, top } = uni.getMenuButtonBoundingClientRect();
  conHeight.value = height + (top - statusBarHeight.value) * 2;

  // #endif
  const defaultSlotContentHeight = ref(uni.upx2px(_.defaultSlotContentHeight));
  const headerHeight = ref<number>(
    statusBarHeight.value + conHeight.value + defaultSlotContentHeight.value,
  );

  const enterOptions = uni.getEnterOptionsSync();
  if (_.transparent === 'auto' && enterOptions.scene !== SceneValuesEnum.TIMELINE_SINGLEPAGE) {
    const opacity_nav = ref<number>(0);
    function PageScroll({ scrollTop }: { scrollTop: number }) {
      const Offset = _.offsetHeight ? _.offsetHeight - headerHeight.value : 100;
      let top = scrollTop / Offset;
      opacity.value = top > 1 ? 1 : top <= 0 ? 0 : top;
      emit('update:opacity', opacity.value);
      const co = [
        baseColor[0] - (baseColor[0] - varietyColor[0]) * opacity.value,
        baseColor[1] - (baseColor[1] - varietyColor[1]) * opacity.value,
        baseColor[2] - (baseColor[2] - varietyColor[2]) * opacity.value,
      ];
      color.value = 'rgb(' + co.join(',') + ')';
      opacity_nav.value = opacity.value === 1 ? 1 : 0;
    }

    watch(opacity_nav, (isK) => {
      uni.setNavigationBarColor({
        frontColor: isK ? '#000000' : '#ffffff',
        backgroundColor: '#ffffff',
        animation: {
          duration: 400,
          timingFunc: 'linear',
        },
      });
    });
    onPageScroll(PageScroll);
  }

  const oldHeaderHeight = toRaw(headerHeight.value);
  function setHeaderHeight(h: number) {
    headerHeight.value = oldHeaderHeight - defaultSlotContentHeight.value + h;
    emit('update:modelValue', headerHeight.value);
  }
  emit('update:modelValue', headerHeight.value);

  function getBottomBox() {
    const query = uni.createSelectorQuery().in(ins.proxy);
    query
      .select('.bottom-box')
      .boundingClientRect((res) => {
        const { height } = res as UniApp.NodeInfo;
        setHeaderHeight(height as number);
      })
      .exec();
  }

  const getBackClass = computed(() => ({
    'backdrop-filter': inIos,
    'box-shadow': _.isBoxShadow,
  }));

  watch(
    () => _.data,
    () =>
      nextTick(() => {
        setTimeout(() => {
          getBottomBox();
        }, 60);
      }),
  );

  onReady(() => getBottomBox());

  const goBack = async () => {
    if (_.isCustomBack) {
      emit('goBack');
      return;
    }
    navigateBack();
  };
</script>

<style lang="scss" scoped>
  .header {
    position: relative;
    height: 128rpx;

    .fixed {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
    }

    .back {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      width: 100%;
      height: 100%;
      z-index: 1;
      background: rgba(255, 255, 255, 0.8);
    }

    .box-shadow {
      box-shadow: 0px 11rpx 54rpx 3rpx rgba(200, 200, 200, 0.2);
    }

    .box {
      position: relative;
      z-index: 10;

      .status-bar {
        height: 20px;
        height: var(--status-bar-height);
      }

      .con {
        position: relative;
        z-index: 10;

        .con-box {
          height: 100%;
          display: flex;
          align-items: center;
          justify-content: center;
          color: #000000;

          .con-title {
            text-align: center;
            max-width: 400rpx;
            font-size: 36rpx;
            // font-weight: bolder;
            line-height: 2;
          }
        }
      }
    }
  }
</style>
